package com.beemans.corekit.localpush;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class PackageWatcher {
    private static PackageWatcher instance;

    private static final String TAG = PackageWatcher.class.getSimpleName();

    @NonNull
    private final Context context;
    @NonNull
    private final HandlerThread handlerThread;
    @NonNull
    private final Handler handler;
    @Nullable
    private PackageChangeListener packageChangeListener;

    private final Map<String, InstalledAppInfo> installedPackages = new HashMap<>();

    private PackageWatcher(@NonNull Context context) {
        this.context = context.getApplicationContext();
        handlerThread = new HandlerThread(TAG);
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
    }

    public static synchronized PackageWatcher getInstance(@NonNull Context context) {
        if (instance == null) {
            instance = new PackageWatcher(context);
        }
        return instance;
    }

    public void setPackageChangeListener(@NonNull PackageChangeListener listener) {
        this.packageChangeListener = listener;
    }

    public void init() {
        handler.post(() -> {
            registerReceiver();
            refreshInstalledPackages();
        });
    }

    @NonNull
    public Map<String, InstalledAppInfo> getInstalledPackages() {
        return new HashMap<>(installedPackages);
    }

    @Nullable
    public InstalledAppInfo getAppInfo(@NonNull String packageName) {
        return installedPackages.get(packageName);
    }

    // -------------------------
    // 已安装应用管理
    // -------------------------

    /**
     * <queries>
     * <intent>
     * <action android:name="android.intent.action.MAIN" />
     * <category android:name="android.intent.category.LAUNCHER" />
     * </intent>
     * <intent>
     * <action android:name="android.intent.action.MAIN" />
     * </intent>
     * <intent>
     * <action android:name="android.intent.action.VIEW" />
     * </intent>
     * </queries>
     */
    @SuppressLint("QueryPermissionsNeeded")
    private void refreshInstalledPackages() {
        try {
            final PackageManager pm = context.getPackageManager();
            final List<PackageInfo> packages = pm.getInstalledPackages(0);
            installedPackages.clear();

            for (PackageInfo pkgInfo : packages) {
                final InstalledAppInfo appInfo = createAppInfo(pkgInfo.packageName);
                if (appInfo != null) {
                    installedPackages.put(pkgInfo.packageName, appInfo);
                }
            }
        } catch (Throwable ignored) {
        }
    }

    @Nullable
    private InstalledAppInfo createAppInfo(@NonNull String packageName) {
        try {
            final PackageManager pm = context.getPackageManager();
            final ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
            final String label = pm.getApplicationLabel(ai).toString();
            final Drawable icon = pm.getApplicationIcon(ai);
            return new InstalledAppInfo(packageName, label, icon);
        } catch (Throwable e) {
            return null;
        }
    }

    // -------------------------
    // 广播注册与监听
    // -------------------------
    private void registerReceiver() {
        try {
            final IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
            filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
            filter.addDataScheme("package");

            ContextCompat.registerReceiver(context, packageReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED);
        } catch (Throwable ignored) {
        }
    }

    public void unregisterReceiver() {
        try {
            context.unregisterReceiver(packageReceiver);
        } catch (Throwable ignored) {
        }
    }

    private final BroadcastReceiver packageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final Uri uri = intent != null ? intent.getData() : null;
            if (uri == null) return;

            final String pkg = uri.getSchemeSpecificPart();
            if (pkg == null) return;

            final String action = intent.getAction();
            if (Intent.ACTION_PACKAGE_ADDED.equals(action) || Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
                handler.post(() -> {
                    final InstalledAppInfo appInfo = createAppInfo(pkg);
                    if (appInfo != null) {
                        installedPackages.put(pkg, appInfo);
                    }

                    if (packageChangeListener != null) {
                        packageChangeListener.onPackageInstalled(appInfo);
                    }
                });
            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                handler.post(() -> {
                    final InstalledAppInfo appInfo = getAppInfo(pkg);
                    installedPackages.remove(pkg);

                    if (packageChangeListener != null) {
                        packageChangeListener.onPackageUninstalled(appInfo);
                    }
                });
            }
        }
    };

    // -------------------------
    // 资源释放
    // -------------------------
    public void release() {
        unregisterReceiver();
        handlerThread.quitSafely();
        instance = null;
    }
}